package com.ayuan.blog.service.impl;

import com.ayuan.blog.bean.ArticleInfo;
import com.ayuan.blog.bean.ArticleSearchBean;
import com.ayuan.blog.bean.RecentArticleSearchBean;
import com.ayuan.blog.dao.ArticleDao;
import com.ayuan.blog.dao.ArticleTagDao;
import com.ayuan.blog.dao.TagDao;
import com.ayuan.blog.domain.Article;
import com.ayuan.blog.domain.ArticleTag;
import com.ayuan.blog.domain.Tag;
import com.ayuan.blog.domain.sch.ArticleSch;
import com.ayuan.blog.service.ArticleService;
import com.ayuan.blog.service.TagService;
import com.github.pagehelper.PageInfo;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.durcframework.core.expression.ExpressionQuery;
import org.durcframework.core.expression.SqlContent;
import org.durcframework.core.expression.subexpression.LikeDoubleExpression;
import org.durcframework.core.expression.subexpression.ValueExpression;
import org.durcframework.core.service.CrudService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@Log4j2
public class ArticleServiceImpl extends CrudService<Article, ArticleDao> implements ArticleService {

    @Autowired
    TagService tagService;
    @Autowired
    ArticleTagDao articleTagDao;
    @Autowired
    TagDao tagDao;

    @Override
    public ArticleInfo findArticleInfoByArticleId(Integer articleId) {
        Article article = this.getDao().get(articleId);
        ArticleInfo articleInfo = new ArticleInfo();
        BeanUtils.copyProperties(article, articleInfo);

        List<Tag> tagList = tagService.findTagByArticleId(articleId);
        if (CollectionUtils.isNotEmpty(tagList)) {
            String tags = tagList.get(0).getTagName();
            for(int i = 1; i < tagList.size(); i++) {
                tags += "," + tagList.get(i).getTagName();
            }
            articleInfo.setTags(tags);
        }

        return articleInfo;
    }

    @Override
    public void saveArticleInfo(ArticleInfo articleInfo) {
        articleInfo.setCreateDate(new Date());
        articleInfo.setUpdateDate(articleInfo.getCreateDate());
        articleInfo.setViewNumber(0);
        articleInfo.setDeleteFlag(0);
        Article article = save(articleInfo);
        if (StringUtils.isNotEmpty(articleInfo.getTags())) {
            List<String> tagList = new ArrayList<String>();
            for (String tag : articleInfo.getTags().split(",")) {
                tagList.add(tag.trim());
            }
        }
        saveArticleTags(articleInfo.getTags(), article.getId());
    }

    @Override
    public void updateArticleInfo(ArticleInfo articleInfo) {
        Date now = new Date();
        Article article = get(articleInfo.getId());
        article.setTitle(articleInfo.getTitle());
        article.setContent(articleInfo.getContent());
        article.setClasfId(articleInfo.getClasfId());
        article.setPicUrl(articleInfo.getPicUrl());
        article.setUpdateDate(now);
        update(article);
        if (StringUtils.isNotEmpty(articleInfo.getTags())) {
            List<String> tagList = new ArrayList<String>();
            for (String tag : articleInfo.getTags().split(",")) {
                tagList.add(tag);
            }
        }
        clearArticleTags(articleInfo.getId());
        saveArticleTags(articleInfo.getTags(), articleInfo.getId());
    }

    @Override
    public void delete(Integer articleId) {
        Article article = this.getDao().get(articleId);
        if (null != article) {
            article.setDeleteFlag(1);
            this.getDao().update(article);
        }
    }

    @Override
    public void view(Integer articleId) {
        try {
            this.getDao().addViewNumber(articleId);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @Override
    public List<ArticleInfo> findAllArticleInfo() {
        ExpressionQuery query = new ExpressionQuery();
        query.addSort("create_date", SqlContent.DESC);
        query.addValueExpression(new ValueExpression("t.delete_flag", 0));
        query.setLimit(10);

        return this.getDao().findAllArticleInfo(query);
    }

    @Override
    public PageInfo<ArticleInfo> findPageArticleInfo(ArticleSch sch) {
        if (sch.getPageIndex() <= 0) {
            sch.setPageIndex(1);
        }
        if (sch.getPageSize() <= 0) {
            sch.setPageSize(10);
        }
        ExpressionQuery query = new ExpressionQuery();
        if (null != sch.getUserIdSch()) {
            query.addValueExpression(new ValueExpression("user_id", sch.getUserIdSch()));
        }
        query.addValueExpression(new ValueExpression("t.delete_flag", 0));
        query.setStart(sch.getStart());
        query.setLimit(sch.getLimit());

        int totalCount = this.getDao().findArticleInfoTotalCount(query);

        PageInfo<ArticleInfo> page = new PageInfo<ArticleInfo>();

        if (totalCount <= 0) {
            return page;
        }

        List<ArticleInfo> list = this.getDao().findArticleInfo(query);
        page.setTotal(totalCount);
        page.setList(list);
        page.setPageSize(sch.getPageSize());
        page.setPageNum(sch.getPageIndex());
        page.setPages((totalCount + sch.getPageSize() - 1) / sch.getPageSize());
        return page;
    }

    @Override
    public List<ArticleInfo> findRecentArticles(RecentArticleSearchBean recentArticleSearchBean) {
        ExpressionQuery query = new ExpressionQuery();

        query.addSort("create_date", "desc");
        query.addValueExpression(new ValueExpression("t.delete_flag", 0));
        query.setStart(0);
        query.setLimit(recentArticleSearchBean.getSize());
        if (null != recentArticleSearchBean.getUserId()) {
            query.addValueExpression(new ValueExpression("user_id", recentArticleSearchBean.getUserId()));
        }

        List<ArticleInfo> list = this.getDao().findArticleInfo(query);

        return list;
    }

    @Override
    public PageInfo<ArticleInfo> findPageArticleInfoByConditions(ArticleSearchBean sch) {
        if (sch.getPageNum() <= 0) {
            sch.setPageNum(1);
        }
        if (sch.getPageSize() <= 0) {
            sch.setPageSize(10);
        }
        ExpressionQuery query = new ExpressionQuery();
        if (null != sch.getUserId()) {
            query.addValueExpression(new ValueExpression("user_id", sch.getUserId()));
        }
        if (StringUtils.isNotEmpty(sch.getSearchValue())) {
            query.addValueExpression(new LikeDoubleExpression("title", sch.getSearchValue()));
            query.addValueExpression(new LikeDoubleExpression("content", sch.getSearchValue()));
        }
        query.addValueExpression(new ValueExpression("t.delete_flag", 0));
        query.setStart(sch.getStart());
        query.setLimit(sch.getPageSize());

        int totalCount = this.getDao().findArticleInfoTotalCount(query);

        PageInfo<ArticleInfo> page = new PageInfo<ArticleInfo>();

        if (totalCount <= 0) {
            return page;
        }

        List<ArticleInfo> list = this.getDao().findArticleInfo(query);

        List<Integer> articleIdList = new ArrayList<Integer>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (ArticleInfo articleInfo : list) {
                articleIdList.add(articleInfo.getId());
            }
            List<ArticleTag> articleTagList = articleTagDao.findListByArticleIds(articleIdList);
            if (CollectionUtils.isNotEmpty(articleTagList)) {
                List<Integer> tagIdList = new ArrayList<Integer>();
                for (ArticleTag articleTag : articleTagList) {
                    if (!tagIdList.contains(articleTag.getTagId())) {
                        tagIdList.add(articleTag.getTagId());
                    }
                }
                List<Tag> tagList = tagDao.findListByIds(tagIdList);

                for (ArticleInfo articleInfo : list) {
                    List<Tag> tempTagList = new ArrayList<Tag>();
                    for (ArticleTag articleTag : articleTagList) {
                        if (articleTag.getArticleId() == articleInfo.getId()) {
                            for (Tag tag : tagList) {
                                if (tag.getId() == articleTag.getTagId()) {
                                    tempTagList.add(tag);
                                    break;
                                }
                            }
                        }
                    }
                    if (CollectionUtils.isNotEmpty(tempTagList)) {
                        articleInfo.setTags(getTagsStr(tempTagList));
                    }
                }
            }
        } else {
            list = new ArrayList<ArticleInfo>();
        }

        page.setTotal(totalCount);
        page.setList(list);
        page.setPageSize(sch.getPageSize());
        page.setPageNum(sch.getPageNum());
        page.setPages((totalCount + sch.getPageSize() - 1) / sch.getPageSize());
        return page;
    }

    private String getTagsStr(List<Tag> tagList) {
        StringBuilder tagsStr = new StringBuilder();
        if (CollectionUtils.isNotEmpty(tagList)) {
            tagsStr.append(tagList.get(0).getTagName());
            for (int i = 1; i < tagList.size(); i++) {
                tagsStr.append(",");
                tagsStr.append(tagList.get(i).getTagName());
            }
        }
        return tagsStr.toString();
    }

    private void saveArticleTags(String tags, Integer articleId) {
        if (StringUtils.isNotEmpty(tags)) {
            Tag tempTag = null;
            ArticleTag tempArticleTag = null;
            for (String tag : tags.split(",")) {
                tempTag = new Tag();
                tempTag.setTagName(tag);
                tempTag.setCreateTime(new Date());
                tempTag.setUpdateTime(tempTag.getCreateTime());
                tempTag = tagService.addTag(tempTag);
                tempArticleTag = new ArticleTag();
                tempArticleTag.setArticleId(articleId);
                tempArticleTag.setTagId(tempTag.getId());
                tempArticleTag.setCreateTime(new Date());
                tempArticleTag.setUpdateTime(tempArticleTag.getCreateTime());
                articleTagDao.save(tempArticleTag);
            }
        }
    }

    private void clearArticleTags(Integer articleId) {
        articleTagDao.delByArticleId(articleId);
    }
}